#include "header.h"

/* Syntax Highlighting is kinda goofy and no where near advanced.
   The goal isn't to be advanced but to give your eyes a little bit
   of contrast.
   Firstly, you can highlight keywords such as "if" or "else". Then,
   you give it the color you want it to be. The general rule of thumb
   is that functions, methods, macros, or statements are given the ID
   of ID_FUNCTION. Varible, types, and other defining syntax is given
   ID_SYMBOL. Secondary type definitions such as "long" in C or
   "default" in JS are generally given TB_DIGIT. Contants such as
   NULL, null, true/false, etc. are given ID_CONSTANT.

   This is very much still a work in progress.

   Key:
   - , means all (excluding symbols)
   - , beginning of line (only highlight when the match is at the
         beginning of the line
   - , complete, all chars
   - , disregard (ignore everything before it)
   - , all printable chars (no spaces, tabs, etc.)
   - , all space chars (spaces, tabs, etc.)
   - , omit, don't highlight this character.
         This is used to reduce the highlight from left to right
   - , exclude, don't highlight this character.
         This is used to reduce the highlight from right to left.
*/

syntax_t csyn[] = {
    {"<>", ID_DIGITS},
    {"if", ID_FUNCTION}, {"else", ID_FUNCTION}, {"for", ID_FUNCTION},
    {"return", ID_FUNCTION}, {"while", ID_FUNCTION},
    {"void", ID_SYMBOL}, {"#", ID_FUNCTION}, {"int", ID_SYMBOL}, {"enum", ID_SYMBOL},
    {"char", ID_SYMBOL}, {"const", ID_DIGITS}, {"unsigned", ID_DIGITS}, {"static", ID_DIGITS},
    {"assert", ID_FUNCTION}, {"break", ID_FUNCTION}, {"switch", ID_FUNCTION},
    {"continue", ID_FUNCTION},
    {"case", ID_FUNCTION}, {"NULL", ID_CONSTANT}, {"long", ID_DIGITS}, {"struct", ID_DIGITS},
    {"typedef", ID_SYMBOL}, {"_t", ID_SYMBOL},
    {"TRUE", ID_CONSTANT}, {"FALSE", ID_CONSTANT}, {NULL}};

syntax_t htmlsyn[] = {
  {"</>", ID_FUNCTION}, {"</>", ID_FUNCTION},
  {"<>", ID_FUNCTION}, {"<!", ID_FUNCTION}, {"<", ID_FUNCTION},
  {NULL}
};

syntax_t jssyn[] = {{"if", ID_FUNCTION}, {"else", ID_FUNCTION}, {"for", ID_FUNCTION},
    {"return", ID_FUNCTION}, {"while", ID_FUNCTION},
    {"const", ID_SYMBOL}, {"let", ID_SYMBOL}, {"var", ID_SYMBOL},
    {"break", ID_FUNCTION}, {"switch", ID_FUNCTION}, {"export", ID_FUNCTION},
    {"typeof", ID_FUNCTION}, {"case", ID_FUNCTION}, {"null", ID_CONSTANT},
    {"import", ID_FUNCTION}, {"from", ID_SYMBOL}, {"default", ID_DIGITS},
    {"undefined", ID_CONSTANT}, {"true", ID_CONSTANT}, {"false", ID_CONSTANT},
    {"function", ID_SYMBOL}, {"new", ID_DIGITS}, {"try", ID_FUNCTION},
    {"catch", ID_FUNCTION}, {"finally", ID_FUNCTION}, {"async", ID_DIGITS},
    {"await", ID_DIGITS}, {"class", ID_FUNCTION},
    {NULL}};

syntax_t tssyn[] = {
    {"interface", ID_FUNCTION}, {"type", ID_FUNCTION}, {"as", ID_DIGITS},
    {"<, , >", ID_FUNCTION}, {"<, >", ID_FUNCTION},
    {"<>", ID_FUNCTION},
    // below is the same as jssyn
    {"if", ID_FUNCTION}, {"else", ID_FUNCTION},
    {"for", ID_FUNCTION},
    {"return", ID_FUNCTION}, {"while", ID_FUNCTION},
    {"const", ID_SYMBOL}, {"let", ID_SYMBOL}, {"var", ID_SYMBOL},
    {"break", ID_FUNCTION}, {"switch", ID_FUNCTION}, {"export", ID_FUNCTION},
    {"typeof", ID_FUNCTION}, {"case", ID_FUNCTION}, {"null", ID_CONSTANT},
    {"import", ID_FUNCTION}, {"from", ID_SYMBOL}, {"default", ID_DIGITS},
    {"undefined", ID_CONSTANT}, {"true", ID_CONSTANT}, {"false", ID_CONSTANT},
    {"function", ID_SYMBOL}, {"new", ID_DIGITS}, {"try", ID_FUNCTION},
    {"catch", ID_FUNCTION}, {"finally", ID_FUNCTION}, {"async", ID_DIGITS},
    {"await", ID_DIGITS}, {"extends", ID_SYMBOL}, {"class", ID_FUNCTION},
    {NULL}};


syntax_t jsxsyn[] = {
    // below is the same as htmlsyn
    {"</>", ID_FUNCTION}, {"</>", ID_FUNCTION},
    {"<>", ID_FUNCTION}, {"<", ID_FUNCTION},
    // below is the same as jssyn
    {"if", ID_FUNCTION}, {"else", ID_FUNCTION},
    {"for", ID_FUNCTION},
    {"return", ID_FUNCTION}, {"while", ID_FUNCTION},
    {"const", ID_SYMBOL}, {"let", ID_SYMBOL}, {"var", ID_SYMBOL},
    {"break", ID_FUNCTION}, {"switch", ID_FUNCTION}, {"export", ID_FUNCTION},
    {"typeof", ID_FUNCTION}, {"case", ID_FUNCTION}, {"null", ID_CONSTANT},
    {"import", ID_FUNCTION}, {"from", ID_SYMBOL}, {"default", ID_DIGITS},
    {"undefined", ID_CONSTANT}, {"true", ID_CONSTANT}, {"false", ID_CONSTANT},
    {"function", ID_SYMBOL}, {"new", ID_DIGITS}, {"try", ID_FUNCTION},
    {"catch", ID_FUNCTION}, {"finally", ID_FUNCTION}, {"async", ID_DIGITS},
    {"await", ID_DIGITS},  {"extends", ID_SYMBOL}, {"class", ID_FUNCTION},
    {NULL}};


syntax_t tsxsyn[] = {
    // below is the same as htmlsyn
    {"</>", ID_FUNCTION}, {"</>", ID_FUNCTION},
    // below is the same as tssyn
    {"<, , >", ID_FUNCTION}, {"<, >", ID_FUNCTION},
    {"<>", ID_FUNCTION},
    // below is the same as htmlsyn
    {"<", ID_FUNCTION},
    // below is the same as tssyn
    {"interface", ID_FUNCTION}, {"type", ID_FUNCTION}, {"as", ID_DIGITS},
    // below is the same as jssyn
    {"if", ID_FUNCTION}, {"else", ID_FUNCTION},
    {"for", ID_FUNCTION},
    {"return", ID_FUNCTION}, {"while", ID_FUNCTION},
    {"const", ID_SYMBOL}, {"let", ID_SYMBOL}, {"var", ID_SYMBOL},
    {"break", ID_FUNCTION}, {"switch", ID_FUNCTION}, {"export", ID_FUNCTION},
    {"typeof", ID_FUNCTION}, {"case", ID_FUNCTION}, {"null", ID_CONSTANT},
    {"import", ID_FUNCTION}, {"from", ID_SYMBOL}, {"default", ID_DIGITS},
    {"undefined", ID_CONSTANT}, {"true", ID_CONSTANT}, {"false", ID_CONSTANT},
    {"function", ID_SYMBOL}, {"new", ID_DIGITS}, {"try", ID_FUNCTION},
    {"catch", ID_FUNCTION}, {"finally", ID_FUNCTION}, {"async", ID_DIGITS},
    {"await", ID_DIGITS}, {"class", ID_FUNCTION},
    {NULL}};


syntax_t awksyn[] = {{"if", ID_FUNCTION}, {"else", ID_FUNCTION}, {"for", ID_FUNCTION},
    {"return", ID_FUNCTION}, {"while", ID_FUNCTION}, {"BEGIN", ID_FUNCTION},
    {"END", ID_FUNCTION},
    {"break", ID_FUNCTION}, {"switch", ID_FUNCTION},
    {"case", ID_FUNCTION}, {"NULL", ID_CONSTANT},{"TRUE", ID_CONSTANT},
    {"FALSE", ID_CONSTANT}, {NULL}};

syntax_t mdsyn[] = {
  {"[]()", ID_CONSTANT}, {"__", ID_CONSTANT}, {"****", ID_FUNCTION},
  {"**", ID_FUNCTION}, {"~~~~", ID_SYMBOL}, {"#", ID_SYMBOL},
  {NULL}};

syntax_t luasyn[] = {
    {"if", ID_FUNCTION}, {"else", ID_FUNCTION}, {"for", ID_FUNCTION},
    {"return", ID_FUNCTION}, {"while", ID_FUNCTION}, {"elseif", ID_FUNCTION},
    {"local", ID_SYMBOL},
    {"assert", ID_FUNCTION}, {"break", ID_FUNCTION}, {"switch", ID_FUNCTION},
    {"continue", ID_FUNCTION}, {"function", ID_FUNCTION}, {"end", ID_FUNCTION},
    {"case", ID_FUNCTION}, {"nil", ID_CONSTANT}, {"then", ID_SYMBOL},
    {"true", ID_CONSTANT}, {"false", ID_CONSTANT}, {NULL}};

/* TODO for haskell:
   foreign
   hiding
   infix, infixl, infixr
   mdo
   newtype
   proc
   rec
   type
   type family
   type instance
*/
syntax_t hssyn[]= {
  {"as", ID_DIGITS}, {"case", ID_FUNCTION}, {"of", ID_DIGITS}, {"class", ID_FUNCTION},
  {"data family", ID_SYMBOL}, {"data instance", ID_SYMBOL}, {"data", ID_SYMBOL},
  {"default", ID_DIGITS}, {"deriving instance", ID_SYMBOL}, {"deriving", ID_SYMBOL},
  {"do", ID_FUNCTION}, {"forall", ID_SYMBOL}, {"if", ID_FUNCTION}, {"else", ID_FUNCTION},
  {"then", ID_DIGITS}, {"module", ID_FUNCTION}, {"where", ID_FUNCTION},
  {"import", ID_FUNCTION}, {"qualified", ID_DIGITS}, {"let", ID_FUNCTION},
  {"in", ID_DIGITS}, {"instance", ID_FUNCTION},
  {NULL}};

/* WIP */
syntax_t datsyn[] = {
  {"-$", ID_FUNCTION}, {NULL},
};

/* WIP */
syntax_t sqlsyn[] = {
  {"SELECT", ID_FUNCTION}, {"select", ID_FUNCTION}, {"FROM", ID_FUNCTION}, {"from", ID_FUNCTION},
  {"WHERE", ID_FUNCTION}, {"where", ID_FUNCTION}, {"ORDER BY", ID_FUNCTION}, {"order BY", ID_FUNCTION},
  {"GROUP BY", ID_FUNCTION}, {"group BY", ID_FUNCTION}, {"HAVING", ID_DIGITS}, {"having", ID_DIGITS},
  {"INSERT INTO", ID_FUNCTION}, {"insert into", ID_FUNCTION},
  {"UPDATE", ID_FUNCTION}, {"update", ID_FUNCTION}, {"DELETE", ID_FUNCTION}, {"delete", ID_FUNCTION},
  {"CREATE", ID_FUNCTION}, {"create", ID_FUNCTION}, {"ALTER", ID_FUNCTION}, {"alter", ID_FUNCTION},
  {"JOIN", ID_SYMBOL}, {"join", ID_SYMBOL}, {"UNION", ID_FUNCTION}, {"union", ID_FUNCTION},
  {"LIKE", ID_FUNCTION}, {"like", ID_FUNCTION}, {"IN", ID_DIGITS}, {"in", ID_DIGITS},
  {"EXISTS", ID_DIGITS}, {"exists", ID_DIGITS}, {"NOT", ID_FUNCTION}, {"not", ID_FUNCTION},
  {"AND", ID_FUNCTION}, {"and", ID_FUNCTION}, {"OR", ID_FUNCTION}, {"or", ID_FUNCTION},
  {"BETWEEN", ID_FUNCTION}, {"between", ID_FUNCTION}, {"DISTINCT", ID_DIGITS}, {"distinct", ID_DIGITS},
  {"NULL", ID_CONSTANT}, {"null", ID_CONSTANT}, {"COUNT", ID_FUNCTION}, {"count", ID_FUNCTION},
  {"SUM", ID_FUNCTION}, {"sum", ID_FUNCTION}, {"AVG", ID_FUNCTION}, {"avg", ID_FUNCTION},
  {"MIN", ID_FUNCTION}, {"min", ID_FUNCTION}, {"MAX", ID_FUNCTION}, {"max", ID_FUNCTION},
  {"AS", ID_DIGITS}, {"as", ID_DIGITS}, {"IF", ID_FUNCTION}, {"if", ID_FUNCTION},
  {"SET", ID_FUNCTION}, {"set", ID_FUNCTION}, {"ADD", ID_FUNCTION}, {"add", ID_FUNCTION},
  {"FALSE", ID_CONSTANT}, {"false", ID_CONSTANT}, {"TRUE", ID_CONSTANT}, {"true", ID_CONSTANT},
  {NULL}
};

syntax_t javasyn[] = {{"if", ID_FUNCTION}, {"else", ID_FUNCTION}, {"for", ID_FUNCTION},
    {"return", ID_FUNCTION}, {"while", ID_FUNCTION},
    {"class", ID_SYMBOL}, {"break", ID_FUNCTION}, {"switch", ID_FUNCTION},
    {"export", ID_FUNCTION}, {"typeof", ID_FUNCTION}, {"case", ID_FUNCTION},
    {"null", ID_CONSTANT}, {"import", ID_FUNCTION}, {"from", ID_SYMBOL}, {"default", ID_DIGITS},
    {"undefined", ID_CONSTANT}, {"true", ID_CONSTANT}, {"false", ID_CONSTANT},
    {"try", ID_FUNCTION}, {"catch", ID_FUNCTION}, {"finally", ID_FUNCTION},
    {"package", ID_FUNCTION}, {"override", ID_DIGITS}, {"private", ID_DIGITS},
    {"public", ID_DIGITS}, {"object", ID_SYMBOL},
    {NULL}};

syntax_t ktsyn[] = {{"if", ID_FUNCTION}, {"else", ID_FUNCTION}, {"for", ID_FUNCTION},
    {"return", ID_FUNCTION}, {"while", ID_FUNCTION},
    {"val", ID_SYMBOL}, {"class", ID_SYMBOL}, {"var", ID_SYMBOL},
    {"break", ID_FUNCTION}, {"switch", ID_FUNCTION}, {"export", ID_FUNCTION},
    {"typeof", ID_FUNCTION}, {"case", ID_FUNCTION}, {"null", ID_CONSTANT},
    {"import", ID_FUNCTION}, {"from", ID_SYMBOL}, {"default", ID_DIGITS},
    {"undefined", ID_CONSTANT}, {"true", ID_CONSTANT}, {"false", ID_CONSTANT},
    {"fun", ID_SYMBOL}, {"lateinit", ID_DIGITS}, {"open", ID_DIGITS},
    {"try", ID_FUNCTION}, {"catch", ID_FUNCTION}, {"finally", ID_FUNCTION},
    {"package", ID_FUNCTION}, {"override", ID_DIGITS}, {"private", ID_DIGITS},
    {"public", ID_DIGITS}, {"object", ID_SYMBOL}, {"companion", ID_DIGITS},
    {NULL}};

syntax_t mksyn[] = {
  {"$()", ID_CONSTANT}, {"?=", ID_CONSTANT}, {"?=", ID_CONSTANT},
  {"+=", ID_CONSTANT}, {"+=", ID_CONSTANT},
  {":=", ID_CONSTANT}, {":=", ID_CONSTANT},
  {":", ID_FUNCTION}, {":", ID_FUNCTION},
  {"=", ID_CONSTANT}, {"=", ID_CONSTANT},
  {NULL}};

syntax_t lispsyn[] = {
  {"'", ID_CONSTANT}, {":", ID_SYMBOL}, {"#:", ID_SYMBOL},
  {"&", ID_DIGITS}, {"^", ID_DIGITS}, {"nil", ID_CONSTANT},
  {"t", ID_CONSTANT},
  {NULL}};

syntax_t cljsyn[] = {
  {"'", ID_CONSTANT}, {"::", ID_SYMBOL}, {":", ID_SYMBOL},
  {"#:", ID_SYMBOL}, {"^", ID_DIGITS}, {"nil", ID_CONSTANT},
  {"true", ID_CONSTANT}, {"false", ID_CONSTANT}, {NULL}};

syntax_t csssyn[] = {
  {":", ID_DIGITS}, {"!important", ID_FUNCTION}, {"@", ID_SYMBOL},
  {NULL}};

syntax_t nixsyn[] = {
  {"let", ID_FUNCTION}, {"in", ID_DIGITS}, {"if", ID_FUNCTION},
  {"then", ID_DIGITS}, {"else", ID_FUNCTION}, {"with", ID_DIGITS},
  {"import", ID_FUNCTION}, {"rec", ID_FUNCTION}, {"inherit", ID_FUNCTION},
  {"assert", ID_SYMBOL}, {"builtins", ID_SYMBOL},
  {"derivation", ID_FUNCTION}, {"callPackage", ID_FUNCTION},
  {"true", ID_CONSTANT}, {"false", ID_CONSTANT},
  {NULL}};

syntax_t shsyn[] = {
  {"export", ID_FUNCTION}, {"if", ID_FUNCTION}, {"then", ID_DIGITS},
  {"else", ID_FUNCTION}, {"fi", ID_FUNCTION}, {"case", ID_FUNCTION},
  {"esac", ID_FUNCTION}, {"for", ID_FUNCTION}, {"do", ID_DIGITS},
  {"done", ID_FUNCTION}, {"while", ID_FUNCTION}, {"until", ID_FUNCTION},
  {"function", ID_FUNCTION}, {"return", ID_FUNCTION},
  {"true", ID_CONSTANT}, {"false", ID_CONSTANT},
  {"echo", ID_FUNCTION}, {"test", ID_FUNCTION},
  {"=", ID_SYMBOL}, {"${}", ID_SYMBOL},
  {"$", ID_SYMBOL},
  {NULL}};

/* list of keywords _must_ end with NULL */
smode_t modes[] = {
  /* programming */
  {".c", "//", "/*", "*/", TRUE, FALSE, "", TRUE, csyn},
  {".h", "//", "/*", "*/", TRUE, FALSE, "", TRUE, csyn},
  {".css", "//", "/*", "*/", FALSE, FALSE, ".-", FALSE, csssyn},
  {".html", "", "<!--", "-->", FALSE, FALSE, "", FALSE, htmlsyn},
  {".js", "//", "/*", "*/", TRUE, TRUE, "", TRUE, jssyn},
  {".jsx", "//", "/*", "*/", TRUE, TRUE, "", TRUE, jsxsyn},
  {".ts", "//", "/*", "*/", TRUE, TRUE, "", TRUE, tssyn},
  {".tsx", "//", "/*", "*/", TRUE, TRUE, "", TRUE, tsxsyn},
  {".lisp", ";;", NULL, NULL, FALSE, FALSE, "-?!_", FALSE, lispsyn},
  {".clj", ";;", NULL, NULL, FALSE, FALSE, "-?!/_", FALSE, cljsyn},
  {".cljs", ";;", NULL, NULL, FALSE, FALSE, "-?!/_", FALSE, cljsyn},
  {".joke", ";;", NULL, NULL, FALSE, FALSE, "-?!/_", FALSE, cljsyn},
  {".hs", "--", NULL, NULL, FALSE, FALSE, "", FALSE, hssyn},
  {".sh", "#", NULL, NULL, FALSE, FALSE, "", FALSE, shsyn},
  {".awk", "#", NULL, NULL, FALSE, FALSE, "", TRUE, awksyn},
  {".java", "//", "/*", "*/", FALSE, FALSE, "", FALSE, javasyn},
  {".kt", "//", "/*", "*/", FALSE, TRUE, "", FALSE, ktsyn},
  {".sql", "--", NULL, NULL, FALSE, FALSE, "", FALSE, sqlsyn},
  {".nix", "#", NULL, NULL, TRUE, TRUE, "", FALSE, NULL},
  {".lua", "--", NULL, NULL, TRUE, FALSE, "", FALSE, luasyn},
  {"makefile", "#", NULL, NULL, TRUE, FALSE, "", FALSE, mksyn},
  {"Makefile", "#", NULL, NULL, TRUE, FALSE, "", FALSE, mksyn},
  {"GNUMakefile", "#", NULL, NULL, TRUE, FALSE, "", FALSE, mksyn},
  {".mk", "#", NULL, NULL, TRUE, FALSE, "", FALSE, mksyn},
  /* non-programming */
  {".md", NULL, NULL, NULL, FALSE, TRUE, "", FALSE, mdsyn},
  {".dat", ";;", NULL, NULL, FALSE, FALSE, ",.", FALSE, datsyn},
  {NULL, NULL, NULL, NULL, FALSE, FALSE, "", TRUE, NULL},
};
